package mk.jug.academy.service;

import mk.jug.academy.model.Event;
import mk.jug.academy.model.Page;
import mk.jug.academy.testing.bdd.IntegrationBehavior;
import mk.jug.academy.testing.factory.EventTestFactory;
import mk.jug.academy.testing.util.TestHelper;

import org.springframework.beans.factory.annotation.Autowired;

import com.googlecode.instinct.marker.annotate.Specification;
import com.googlecode.instinct.marker.annotate.Specification.SpecificationState;
import com.googlecode.instinct.marker.annotate.Subject;

/**
 * An integration test unit covering the behavior exhibited regarding the
 * {@link EventLifecycle} management process.
 *
 * @author Ice.Penov
 */
public class EventLifecycle extends IntegrationBehavior {
	
	private static final int ITEMS_PER_PAGE = 2;
	@Autowired private EventService eventService;
	
	@Subject private Event event;
	@Subject private Event event1;
	@Subject private Event event2;
	@Subject private Event event3;
	
	@Override
	protected void beforeHook() {
		event = EventTestFactory.createEvent();
		event1 = EventTestFactory.createEvent();
		event2 = EventTestFactory.createEvent();
		event3 = EventTestFactory.createEvent();
		TestHelper.init(eventService);
	}
	
	/**
	 * User action:
	 * Create an {@link Event}.
	 * 
	 * Expected behavior:
	 * 1. Found the {@link Event} in the event list.
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void createNewEvent() {
		eventService.createEvent(event);
		//expectations.
		expect.that(eventService.list(1, ITEMS_PER_PAGE).getItems()).containsItem(event);
	}
	
	/**
	 * User action:
	 * Removes an existing {@link Event}.
	 * 
	 * Expected behavior:
	 * 1. The {@link Event} is no longer in the event list.
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void removeExistingEvent() {
		eventService.createEvent(event);
		eventService.removeEvent(event);
		//expectations.
		expect.that(eventService.list(1, ITEMS_PER_PAGE).getItems()).isEmpty();
	}
	
	/**
	 * User action:
	 * Edit the event properties.
	 * 
	 * Expected behavior:
	 * 1. The changed properties are persisted.
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void editEventProperties() {
		TestHelper.prepareEvent(event);
		event.setMessage("Changed");
		event.setMessageCode("Changed");
		eventService.saveChanges(event);
		Event loaded = eventService.load(event.getId());
		expect.that(loaded.getMessage()).isEqualTo(event.getMessage());
		expect.that(loaded.getMessageCode()).isEqualTo(event.getMessageCode());
	}
	
	/**
	 * User action:
	 * Fetch the {@link Event}s in a paged manner.
	 * 
	 * Expected behavior:
	 * List the records as expected.
	 */
	@Specification(state = SpecificationState.COMPLETE)
	public void navigateEventsUsingPaging() {
		TestHelper.prepareEvent(event1);
		TestHelper.prepareEvent(event2);
		TestHelper.prepareEvent(event3);
		Page<Event> page1 = eventService.list(1, ITEMS_PER_PAGE); 
		Page<Event> page2 = eventService.list(2, ITEMS_PER_PAGE); 
		Page<Event> page3 = eventService.list(3, ITEMS_PER_PAGE);
		//expectations.
		//sizing.
		expect.that(page1.getTotalCount()).isEqualTo(3);
		expect.that(page2.getTotalCount()).isEqualTo(3);
		expect.that(page3.getTotalCount()).isEqualTo(3);
		expect.that(page1.getItems()).isOfSize(2);
		expect.that(page2.getItems()).isOfSize(1);
		expect.that(page3.getItems()).isEmpty();
		//check items of pages.
		expect.that(page1.getItems()).containsItems(event3, event2);
		expect.that(page2.getItems()).containsItem(event1);
	}
	
}
